import { FilterQuery, MongoClient, OptionalId } from "mongodb";
import { FaucetInterface } from "../model";

export interface BaseMongoModel {
    _id?: string
}
export class BaseMongoClient<T extends BaseMongoModel> {
    constructor(
        protected mongodb: MongoClient,
        protected db: string,
        protected collection: string
    ) { }

    get col() {
        return this.mongodb.db(this.db).collection<T>(this.collection)
    }

    async insertMany(data: OptionalId<T>[]) {
        const { insertedIds } = await this.col.insertMany(data)
        return insertedIds
    }

    async insert(data: OptionalId<T>) {
        const { insertedIds } = await this.col.insert(data)
        return insertedIds
    }

    async createIndex(config: any) {
        let indexName: string = config.indexName
        let expireAfterSeconds: number = config.expireAfterSeconds
        this.col.createIndex({ indexName: 1 }, { expireAfterSeconds: expireAfterSeconds })
    }

    async getOne(req: { condition: FilterQuery<T>, projection?: object }) {
        const { condition, projection = {} } = req
        let res = await this.col.findOne(condition, projection)
        return res;
    }
    // async getOne(req: {condition:FilterQuery<T>,projection:object}) {
    //     let res = await this.col.findOne(req)
    //     return res;        
    // }

    async getMany(req: { sort?: string, condition?: FilterQuery<T | string> } = {}): Promise<T[]> {
        const { sort, condition = {} } = req
        const options: any = {}
        if (sort) {
            options.sort = { sort: 1 }
        }
        const res = await this.col.find(condition, options).toArray()
        return res
    }

    async getManyLimit(req: { sort?: string, limit?: number, skip?: number, condition?: FilterQuery<T | string> } = {}): Promise<T[]> {
        const { sort, limit = 100, skip = 0, condition = {} } = req
        const options: any = {}

        if (sort) {
            options.sort = sort
        }
        options.limit = limit
        options.skip = skip * limit
        // console.log(condition)
        const res = await this.col.find(condition, options).toArray()
        return res
    }

    async aggregate() {



    }




    async updateOne(req: T) {
        const { _id } = req

        if (!_id) {
            throw new Error('_id is undefined')
        }

        delete req._id

        await this.col.updateOne({ _id } as any, { $set: req })
    }

    async getStats() {
        return this.col.stats()
    }

    async delete(req: FilterQuery<T>) {
        await this.col.deleteMany(req)
    }

}

export interface MongodbClientConfig {
    uri: string
    db: string
    col: string
}

export async function createBaseMongoClient<T>(config: MongodbClientConfig) {
    const { db, uri, col } = config
    const mongodb = await MongoClient.connect(uri, { useUnifiedTopology: true })
    const client = new BaseMongoClient<T>(mongodb, db, col)
    return client
}


